Skip to content

fix(actions): async DB compatibility for 5 plugins#109

Merged
Fu-Jie merged 1 commit into
mainfrom
fix/async-db-compat-multi-plugin
Jul 14, 2026
Merged

fix(actions): async DB compatibility for 5 plugins#109
Fu-Jie merged 1 commit into
mainfrom
fix/async-db-compat-multi-plugin

Conversation

@Fu-Jie

@Fu-Jie Fu-Jie commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

Unifies the async DB compatibility fix across 5 action plugins that have openwebui_id metadata. Follows the same approach as #107 (async-context-compression) — replace fragile version-string detection with runtime coroutine detection.

Background

OWUI >= 0.9.0 turned Users.get_user_by_id, Chats.get_chat_by_id, Models.get_model_by_id into coroutines. The previous _owui_version_ge("0.9.0") guard is unreliable in isolated filter/action sandboxes: from open_webui.env import VERSION can fail and fall back to "0.0.0", causing async methods to be called synchronously and raising TypeError: object coroutine can't be used in 'await'. Originally reported in #101.

Fix

_call_db now uses iscoroutinefunction(method) + asyncio.iscoroutine(res) instead of version-string comparison:

async def _call_db(method, *args, **kwargs):
    if iscoroutinefunction(method):
        return await method(*args, **kwargs)
    res = method(*args, **kwargs)
    if asyncio.iscoroutine(res):
        return await res
    return res

Two bug patterns

Class A — existing _call_db using version-string check (6 files):

  • export_to_docxexport_to_word.py, export_to_word_cn.py
  • smart-mind-mapsmart_mind_map.py
  • infographicinfographic.py
  • export_to_excelexport_to_excel.py, export_to_excel_cn.py

Class B — no _call_db helper, called Users.get_user_by_id() synchronously (2 files):

  • flash-cardflash_card.py, flash_card_cn.py (added helper + wrapped call)

Version bumps

Plugin Old New
smart-mind-map 1.0.2 1.0.3
infographic 1.6.2 1.6.3
flash-card 0.2.4 0.2.5
export_to_excel 0.3.10 0.3.11
export_to_docx 0.5.2 0.5.3

Docs

  • Bilingual release notes (v{version}.md + v{version}_CN.md) for all 5 plugins
  • README / README_CN updated with version badges + What's New sections
  • docs/plugins/actions/index.md and index.zh.md version fields updated
  • Stale version-badges in smart-infographic.md, smart-infographic.zh.md, export-to-word.md, export-to-word.zh.md bumped

Note on check_version_consistency.py

The script reports 2 false positives (export_to_excel_cn.py and export_to_word_cn.py) because its regex version: also matches required_open_webui_version: 0.10.2. Running --fix would corrupt that line, so I left the script alone. The actual version: metadata in all 8 .py files is correct.

Refs: #101, #107

Replace fragile version-string check (_owui_version_ge) with runtime
coroutine detection (iscoroutinefunction + asyncio.iscoroutine) in the
_call_db helper. In isolated filter/action sandboxes, importing
open_webui.env.VERSION can fail and fall back to "0.0.0", causing
async DB methods (Users.get_user_by_id, Chats.get_chat_by_id,
Models.get_model_by_id) to be called synchronously on OWUI >= 0.9.0
and raising "TypeError: object coroutine can't be used in 'await'".

Two bug patterns addressed:
- Class A (6 files): existing _call_db helper using version-string
  check, switched to iscoroutinefunction.
  export_to_docx (export_to_word.py, export_to_word_cn.py)
  smart-mind-map (smart_mind_map.py)
  infographic (infographic.py)
  export_to_excel (export_to_excel.py, export_to_excel_cn.py)
- Class B (2 files): no _call_db helper, called
  Users.get_user_by_id() synchronously. Added helper and wrapped call.
  flash-card (flash_card.py, flash_card_cn.py)

Version bumps and bilingual release notes for all 5 plugins.
Index files and docs version-badges updated.

Refs: #101, #107
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Plugin Version Check / 插件版本检查

版本更新检测通过!PR 包含版本变化和更新说明。

Version check passed! PR contains version changes and update description.


版本变化 / Version Changes

Plugin Updates


This comment was generated automatically. / 此评论由自动生成。

@Fu-Jie
Fu-Jie merged commit 3c16fbf into main Jul 14, 2026
1 check passed
@Fu-Jie
Fu-Jie deleted the fix/async-db-compat-multi-plugin branch July 14, 2026 07:12

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

本次拉取请求主要更新了多个 OpenWebUI 插件(包括 Word 导出、Excel 导出、闪记卡、智能信息图和思维导图),旨在解决 OpenWebUI >= 0.9.0 / v0.10.1 上的异步数据库兼容性问题。修改中引入或优化了 _call_db 辅助函数,通过 iscoroutinefunctionasyncio.iscoroutine 进行运行时协程检测,从而替代了此前不稳定的版本号判断。审查意见指出,仅使用 asyncio.iscoroutine(res) 无法检测到其他可等待对象(如 Future、Task 或自定义 awaitable),建议将其替换为 inspect.isawaitable(res) 以提升代码的健壮性与前瞻性。

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +104 to +105
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Comment on lines +105 to +106
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Comment on lines +50 to +51
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Comment on lines +49 to +50
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Comment on lines +27 to +28
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Comment on lines +27 to +28
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Comment on lines +45 to +46
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Comment on lines +62 to +63
if asyncio.iscoroutine(res):
return await res

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using asyncio.iscoroutine(res) only detects coroutine objects created by async def functions. It will return False for other awaitable objects like asyncio.Future, asyncio.Task, or custom awaitables (objects implementing __await__).

To make this helper fully robust and future-proof against any awaitable database responses, use inspect.isawaitable(res) instead.

Note: Remember to update the import at the top of the file to:

from inspect import iscoroutinefunction, isawaitable
Suggested change
if asyncio.iscoroutine(res):
return await res
if isawaitable(res):
return await res

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant